package plus;
import java.util.*;
import java.io.*;
public final class Scan {
  static enum Start {
    inStr(40,40), init(41,41),;
    final int any, bol;
    Start(int any, int bol) { this.any=any; this.bol=bol; }
  }
  private int[] accept = {0,25,22,10,23,3,17,17,17,15,19,26,24,1,11,4,13,8,5,17,18,9,12,21,7,14,11,6,20,16,2,0,17,15,24,0,17,24,0,17,0,0,0,0,0,0,0,0,0,24,};
  private int[][] bounds = {
		{0,},
		{0,},
		{0,},
		{0,},
		{0,},
		{0,},
		{0,10,11,13,14,},
		{0,61,62,},
		{0,},
		{0,48,58,},
		{0,},
		{0,},
		{0,48,58,65,71,97,103,},
		{0,},
		{0,10,11,},
		{0,},
		{0,48,58,65,91,95,96,97,123,},
		{0,},
		{0,},
		{0,62,63,},
		{0,10,11,13,14,34,35,92,93,},
		{0,},
		{0,9,10,11,13,14,32,33,35,36,},
		{0,},
		{0,},
		{0,46,47,48,58,69,70,101,102,},
		{0,},
		{0,},
		{0,},
		{0,},
		{0,},
		{0,48,58,65,91,95,96,97,123,},
		{0,61,62,},
		{0,48,58,69,70,101,102,},
		{0,48,58,65,71,97,103,},
		{0,10,11,13,14,},
		{0,61,62,},
		{0,48,58,65,91,95,96,97,123,},
		{0,48,58,65,71,97,103,},
		{0,61,62,},
		{0,10,11,13,14,34,35,92,93,},
		{0,9,10,11,13,14,32,33,34,35,36,40,41,42,43,45,46,47,48,58,59,60,61,62,63,64,65,91,92,93,94,95,97,123,124,125,126,},
		{0,43,44,45,46,48,58,},
		{0,48,58,},
		{0,10,11,13,14,34,35,39,40,48,49,85,86,92,93,97,98,99,102,103,110,111,114,115,116,117,118,119,120,121,},
		{0,48,58,},
		{0,9,10,11,13,14,32,33,35,36,},
		{0,48,58,65,71,97,103,},
		{0,48,58,65,71,97,103,},
		{0,},
  };
  private int[][] edges = {
		{0,},
		{0,},
		{0,},
		{0,},
		{0,},
		{0,},
		{35,26,35,14,35,},
		{0,24,0,},
		{0,},
		{0,9,0,},
		{0,},
		{0,},
		{0,48,0,48,0,48,0,},
		{0,},
		{0,26,0,},
		{0,},
		{0,16,0,16,0,16,0,16,0,},
		{0,},
		{0,},
		{0,30,0,},
		{20,0,20,0,20,0,20,0,20,},
		{0,},
		{0,46,26,0,14,0,46,0,35,0,},
		{0,},
		{0,},
		{0,43,0,25,0,42,0,42,0,},
		{0,},
		{0,},
		{0,},
		{0,},
		{0,},
		{0,4,0,4,0,4,0,4,0,},
		{0,27,0,},
		{0,33,0,42,0,42,0,},
		{0,38,0,38,0,38,0,},
		{35,26,35,14,35,},
		{0,13,0,},
		{0,31,0,31,0,31,0,31,0,},
		{0,2,0,2,0,2,0,},
		{0,17,0,},
		{20,11,20,11,20,1,20,44,20,},
		{8,22,26,8,14,8,22,39,29,6,8,21,3,18,8,19,8,18,25,36,8,32,8,7,8,5,16,21,8,3,15,8,16,21,8,3,8,},
		{0,45,0,45,0,9,0,},
		{0,33,0,},
		{49,0,49,0,49,10,49,10,49,23,49,37,49,10,49,28,28,49,28,49,28,49,28,49,28,12,28,49,34,49,},
		{0,9,0,},
		{0,46,26,0,14,0,46,0,35,0,},
		{0,38,0,38,0,38,0,},
		{0,47,0,47,0,47,0,},
		{0,},
  };
  private int left, mark, right;
  public Start start;
  public int tabwidth=4;
  public int line, col;
  private static final int BUFSIZ = 1024*4;
  private Reader yy_input;
  private char[] yy_buffer = new char[BUFSIZ];
  private int buflen;
  void reset(Reader yy_input) throws IOException {
    this.yy_input = yy_input;
    buflen = yy_input.read(yy_buffer);
    line=1; col=0; start = Start.init;
    left=0; mark=0;
  }
  public Scan(Reader yy_input) throws IOException { reset(yy_input); }
  public void advance() { while (left<mark) switch (yy_buffer[left++]) {
  case '\t': col=(col/tabwidth+1)*tabwidth; break;
  case '\r': if(left<mark&&yy_buffer[left]=='\n')left++;
  case '\n': col=0; line++; break;
  default: col++;
  }}
  public String text() { return new String(yy_buffer, left, mark-left); }
  public String text(int a, int b) { return new String(yy_buffer, left+a, mark-left-a-b); }
  public int length() { return mark-left; }
  public char charAt(int p) { return yy_buffer[left+p]; }
  public plus.decl.Unit scan() throws IOException,Parse.Error {
    scan: while (true) {
      advance();
      int q = col==0?start.bol:start.any;
      right=left; int rule=0;
      token: while (q>0) {
        if (accept[q]>0) { mark = right; rule=accept[q]; }
        if (right >= buflen) {
          // scanner bumped against end of buffer. Are we at EOF?
          if (buflen<BUFSIZ) { // Yes, in this case.
            if (left==right) break scan; else break token;
          }
          // OK, not necessarily. First try to make more room.
          if (left==0) throw new RuntimeException("Too long of a token! Line "+line);
          // -- Slide uneaten characters to the left
          for (int i=left, j=0; i<buflen; i++,j++) yy_buffer[j] = yy_buffer[i];
          // -- Adjust buffer control variables to match
          buflen -= left; right -= left; mark -= left; left=0;
          // Now can we read any more from the file?
          int more = yy_input.read(yy_buffer, buflen, BUFSIZ-buflen);
          if (more>0) buflen += more; // Got more text...
          else { // We really were at EOF after all...
            if (left==right) break scan; else break token;
          }
        }
        q = edges[q][find(bounds[q], yy_buffer[right])];right++;
      }
      switch (rule) {
      case 0: /* Default Rule */ System.out.append(yy_buffer[mark]);mark++; break;
      case 1: /* line 31 */ p.take(Parse.t_BECOMES); break;
      case 2: /* line 32 */ p.take(Parse.t_ANSWER); break;
      case 3: /* line 33 */ p.take(Parse.t_SCOPE); break;
      case 4: /* line 35 */ p.take(Parse.t_EXPOP, text()); break;
      case 5: /* line 36 */ p.take(Parse.t_MULOP, text()); break;
      case 6: /* line 37 */ p.take(Parse.t_LE); break;
      case 7: /* line 38 */ p.take(Parse.t_GE); break;
      case 8: /* line 39 */ p.take(Parse.t_NE); break;
      case 9: /* line 43 */ parDepth++; p.take(Parse.chr(charAt(0))); break;
      case 10: /* line 44 */ parDepth--; p.take(Parse.chr(charAt(0))); break;
      case 11: /* line 46 */ if (0==parDepth && col>0) p.take(Parse.t_EOL_); break;
      case 12: /* line 47 */ ; break;
      case 13: /* line 49 */ word(text()); break;
      case 14: /* line 50 */ p.take(Parse.t_INT, text()); break;
      case 15: /* line 51 */ p.take(Parse.t_REAL, text()); break;
      case 16: /* line 53 */ sb = new StringBuilder(); start = Start.inStr; break;
      case 17: /* line 56 */ p.take(Parse.chr(charAt(0))); break;
      case 18: /* line 59 */ sb.append(text()); break;
      case 19: /* line 60 */ sb.append(charAt(1)); break;
      case 20: /* line 61 */ sb.append((char)(7+"abtnvfr".indexOf(charAt(1)))); break;
      case 21: /* line 62 */ sb.append((char)0); break;
      case 22: /* line 63 */ sb.append((char)Integer.parseInt(text(2,0), 16)); break;
      case 23: /* line 64 */ sb.append(Character.toChars(Integer.parseInt(text(2,0), 16))); break;
      case 24: /* line 65 */ Gripe.lineNr = line; Gripe.toss("Unrecognized escape sequence "+text()); break;
      case 25: /* line 66 */ p.take(Parse.t_STRING, sb.toString()); start = Start.init; break;
      case 26: /* line 67 */ Gripe.lineNr = line; Gripe.toss("End of line in string"); break;
      }
    }
p.take(Parse.t_EOL_); return p.finish();
 	}
  private static int find(int[] is, int c) {
    int l=0, r=is.length;
    while (l<r) { int m=(l+r)/2; if (is[m]>c) r=m; else l=m+1; }
    return l-1;
  }
private StringBuilder sb;
public Parse p = new Parse();
{ p.scanner = this; }
private int parDepth = 0, lastEND = 0;
// Reserved words. Case senseless, which seems nice...
@SuppressWarnings("serial")
Map<String,Integer> reserved = new HashMap<String,Integer>() {{
	put("not", Parse.t_NOT);
	put("and", Parse.t_AND);
	put("or", Parse.t_OR);
	put("xor", Parse.t_XOR);
	put("eqv", Parse.t_EQV);
	put("div", Parse.t_MULOP);
	put("mod", Parse.t_MULOP);
	put("shr", Parse.t_BITROT);
	put("shrx", Parse.t_BITROT);
	put("shl", Parse.t_BITROT);
	put("rol", Parse.t_BITROT);
	put("ror", Parse.t_BITROT);
	put("as", Parse.t_AS);
	put("begin", Parse.t_BEGIN);
	put("break", Parse.t_BREAK);
	put("call", Parse.t_CALL);
	put("case", Parse.t_CASE);
	put("class", Parse.t_CLASS);
	put("do", Parse.t_DO);
	put("else", Parse.t_ELSE);
	put("end", Parse.t_END);
	put("evaluate", Parse.t_EVALUATE);
	put("false", Parse.t_FALSE);
	put("for", Parse.t_FOR);
	put("function", Parse.t_FUNCTION);
	put("given", Parse.t_GIVEN);
	put("if", Parse.t_IF);
	put("interface", Parse.t_INTERFACE);
	put("implementation", Parse.t_IMPLEMENTATION);
	put("is", Parse.t_IS);
	put("module", Parse.t_MODULE);
	put("new", Parse.t_NEW);
	put("next", Parse.t_NEXT);
	put("nil", Parse.t_NIL);
	put("nop", Parse.t_NOP);
	put("of", Parse.t_OF);
	put("procedure", Parse.t_PROCEDURE);
	put("program", Parse.t_PROGRAM);
	put("record", Parse.t_RECORD);
	put("repeat", Parse.t_REPEAT);
	put("then", Parse.t_THEN);
	put("true", Parse.t_TRUE);
	put("typedef", Parse.t_TYPEDEF);
	put("until", Parse.t_UNTIL);
	put("uses", Parse.t_USES);
	put("using", Parse.t_USING);
	put("var", Parse.t_VAR);
	put("while", Parse.t_WHILE);
}};
private void word(String s) throws Error, Parse.Error {
	String canonical = s.toLowerCase();
	Integer i = reserved.get(canonical);
	if (i == null) p.take(Parse.t_NAME, Unique.String(s));
	else switch(i) {
	case Parse.t_MULOP:
		p.take(i.intValue(), Unique.String(canonical));
		break;
	case Parse.t_END:
		// We simulate extra EOL tokens between END tokens on the same line.
		// This solves one parsing puzzle.
		if (line == lastEND) p.take(Parse.t_EOL_);
		lastEND = line;
		// fall through...
	default: p.take(i.intValue());
	}
}
}
